package com.dataex.dbtool;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.LoggerFactory;

public class ImpBeanUtil {

	public interface CallBackIntface {
		boolean doTrans(Map<String, Object> outMap, String curKey, Object curObj );
	}

	public interface SetObjectCallBack {
		int doSetObject(Object obj, Field field, Map<String, Object> mapData);
	}

	private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ImpBeanUtil.class);

	
	/**
	 * 对象转数组
	 * 
	 * @param obj
	 * @return
	 */
	public static byte[] toByteArray(Object obj) {
		byte[] bytes = null;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			ObjectOutputStream oos = new ObjectOutputStream(bos);
			oos.writeObject(obj);
			oos.flush();
			bytes = bos.toByteArray();
			oos.close();
			bos.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		return bytes;
	}

	/**
	 * 数组转对象
	 * 
	 * @param bytes
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T toObject(byte[] bytes) {
		if (bytes == null)
			return null;
		Object obj = null;
		try {
			ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
			ObjectInputStream ois = new ObjectInputStream(bis);
			obj = ois.readObject();
			ois.close();
			bis.close();
			return (T)obj;
		} catch (IOException ex) {
			logger.error("", ex);
		} catch (ClassNotFoundException ex) {
			logger.error("", ex);
		}
		return null;
	}

	static public Object ResultSetToObj(ResultSet dbO, @SuppressWarnings("rawtypes") Class clazz, Object inObj)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, SQLException {
		if (dbO == null) {
			return null;
		}

		Object obj = inObj;

		if (obj == null)
			obj = clazz.newInstance();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			String fieldName = field.getName();
			if ( Modifier.isStatic( field.getModifiers()) )
				continue;
			
			if (field.getType() == Long.class ) {
				field.set(obj, dbO.getLong(fieldName));
			} else if (field.getType() == Integer.class) {
				field.set(obj, dbO.getInt(fieldName));
			} else if (field.getType() == String.class) {
				field.set(obj, dbO.getString(fieldName));
			} else {
				
			}
		}
		return obj;
	}
	
	
	/**
	 * @return
	 */
	/**
	 * 将 mongodb  DBOject 根据变量名称, 转换为对应的对象
	 * DBObject 没有对象的 field时候, 返回默认 object 对象
	 * @param dbO DBObject
	 * @param className  类名称
	 * @return 成功返回 object, 否则返回null
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
//	static public Object MongoDbObjectToObj(DBObject dbO, String className, Object inObj) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//		if (dbO == null) {
//			return null;
//		}
//	
//		Class<?> clazz = Class.forName(className);
//		Object obj = inObj;
//		if ( obj == null )
//			obj = clazz.newInstance();
//		Field[] fields = clazz.getDeclaredFields();
//		for (Field field : fields) {
//			String fieldName = field.getName();
//			if ( dbO.containsField(fieldName) )
//			{
//				try {
//					field.set(obj, dbO.get(fieldName));
//				} catch (Exception e) {
//					// TODO: handle exception
//				}
//				
//			}
//		}
//
//		return obj;
//	}	
//		
//	
		
	/**
	 * 实现自动 thrifobj 转换到 map<string,object>, 转而转换成json string, 内部过滤 metaDataMap 对象
	 * 
	 * @param thrifObj 
	 * @param call 回调, 可实现部分变量类型转换, 名称转换
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	static public Map<String, Object> ThriftObjToMap(Object thrifObj, boolean bAddNull, Map<String, Class> typeMap,
			CallBackIntface call) {
		Map<String, Object> inMap = new HashMap<String, Object>();
		Field[] fields = thrifObj.getClass().getDeclaredFields();
		try {
			Object oval = null;
			for (Field field : fields) {
				field.setAccessible(true);
				// static member, pass
				if (Modifier.isStatic(field.getModifiers()))
					continue;

				// thrift 内部缓存对象, 过滤掉{__isset_bitfield=1, err_msg=失败, err_code=1, optionals={}}
				if (field.getName().equals("metaDataMap") || 
						field.getName().indexOf("__isset_bit") == 0 || field.getName().indexOf("optionals") == 0 )
					continue;
				oval = null;
				
				//获得对象,执行解析
				Object o = field.get(thrifObj);
				if ( o != null )
					oval = ThriftObjToMap_BaseType( o, bAddNull, typeMap, call );	     
				
				if (typeMap != null )
					typeMap.put(field.getName(), o.getClass());
					
				//数值为 null, bAddNull false, 不生成map中
            	boolean bAdd = true;
            	if ( call != null )
            		bAdd = call.doTrans(inMap, field.getName(), oval);
            	if ( bAdd )
            	{
            		if ( !bAddNull && oval == null )
            			;
            		else
            			inMap.put(field.getName(), oval);	
            	}
			}
		} catch (IllegalArgumentException | IllegalAccessException e) {
			logger.info(""+e);
		}  			
		return inMap;
	}
	
	/**
	 * 转换子函数, double, string, integer, set, list, map 等作为基本对象处理, 否则按照thrift object 对象处理
	 * @param thrifObj
	 * @param call
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	@SuppressWarnings("rawtypes")
	static public Object ThriftObjToMap_BaseType(Object thrifObj, boolean bAddNull, Map<String, Class> typeMap,
			CallBackIntface call) throws IllegalArgumentException, IllegalAccessException {

		Object oval = null;

		// 普通基本数据类型
		if (thrifObj.getClass() == Double.class || thrifObj.getClass() == Long.class
				|| thrifObj.getClass() == Byte.class || thrifObj.getClass() == String.class
				|| thrifObj.getClass() == ByteBuffer.class || thrifObj.getClass() == Integer.class
				|| thrifObj.getClass() == Boolean.class ) {
				oval = thrifObj;
		}
		else if (thrifObj instanceof  Enum){
			oval = new Integer(((Enum)thrifObj).ordinal());
		}
		// list 集合对象, 没有子元素递归处理
		else if (thrifObj instanceof Set<?>) {
			@SuppressWarnings("unchecked")
			Set<Object> objSet = (Set<Object>) thrifObj;
			Set<Object> outSet = new HashSet<Object>();
			for (Object j : objSet) {

				Object o = ImpBeanUtil.ThriftObjToMap_BaseType(j, bAddNull, typeMap, call);
				if (o == null)
					continue;
				outSet.add(o);
			}
		}// list
		else if (thrifObj instanceof List<?>) {
			@SuppressWarnings("unchecked")
			List<Object> objList = (List<Object>) thrifObj;
			List<Object> outList = new ArrayList<Object>();
			for (Object j : objList) {

				Object o = ImpBeanUtil.ThriftObjToMap_BaseType(j, bAddNull, typeMap, call);
				if (o == null)
					continue;
				outList.add(o);
			}
			oval = outList;
		}// map
		else if (thrifObj instanceof Map<?, ?>) {
			@SuppressWarnings("unchecked")
			Map<Object, Object> objList = (Map<Object, Object>) thrifObj;
			Map<Object, Object> outMap = new HashMap<Object, Object>();
			for (Map.Entry<Object, Object> en : objList.entrySet()) {
				Object key = ThriftObjToMap_BaseType(en.getKey(), bAddNull, typeMap, call);
				Object val = ThriftObjToMap_BaseType(en.getValue(), bAddNull, typeMap, call);
				outMap.put(key, val);
			}
			oval = outMap;
		}// 发现不是基本类型, 安装 thrift object 对象处理
		else {
			Map<String, Object> subMap = ThriftObjToMap(thrifObj, bAddNull, typeMap, call);
			oval = subMap;
		}
		return oval;
	}

	/**
	 * 
	 * @param mapObj
	 * @param clazz
	 * @param inObj
	 * @param fieldMap
	 * @param type
	 *            1: fieldmap 中字段替换, 2: 不包含字段, 3: 只包含fieldmap 中字段
	 * @return
	 */
	static public Object MapObjectToObject(Map<String, Object> mapObj, Class<?> clazz, Object inObj,
			final Map<String, String> fieldMap, final int type, SetObjectCallBack call) {

		Object obj = inObj;
		if (obj == null) {
			try {
				obj = clazz.newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				logger.info("" + e);
				return null;
			}
		}

		Field[] fields = obj.getClass().getDeclaredFields();
		try {

			for (Field field : fields) {
				field.setAccessible(true);
				// static member, pass
				if (Modifier.isStatic(field.getModifiers()))
					continue;

				// thrift 内部缓存对象, 过滤掉
				if (field.getName().equals("metaDataMap") || field.getName().indexOf("__isset") >= 0
						|| field.getName().indexOf("optionals") >= 0)
					continue;

				int bNeedSet = 1; // 1 继续, 0 不进行, -1 失败
				if (call != null)
					bNeedSet = call.doSetObject(obj, field, mapObj);

				if (bNeedSet == 1) {
					Ref<Object> retObj = getMapDataMore(type, fieldMap, field, mapObj);
					switch (retObj.c) {
					case 1:
						if ( retObj.v != null ){
							field.set(obj, retObj.v);	
						}
						else {
							logger.info("null value, not set, fieldName:{}, mapped name:{}", field.getName(), fieldMap.get(field.getName()));
						}
						break;
					case 2:
						break;
					case 0:
						if ( mapObj.get(field.getName()) != null )
							field.set(obj, mapObj.get(field.getName()));
						else {
							logger.info("null value, not set, fieldName:{}", field.getName());
						}
						break;
					case -1:
						return null;
					}
				} else if (bNeedSet == -1)
					return null;
			}
		} catch (IllegalArgumentException | IllegalAccessException e) {
			logger.info("" + e);
			return null;
		}
		return obj;
	}
	
	public static void ThriftObjectInitNull(Object thrifObj){
		Field[] fields = thrifObj.getClass().getDeclaredFields();
		try {
			for (Field field : fields) {
				field.setAccessible(true);
				
				// static member, pass
				if (Modifier.isStatic(field.getModifiers()))
					continue;

				// thrift 内部缓存对象, 过滤掉
				if (field.getName().equals("metaDataMap"))
					continue;
				field.setAccessible(true);

				// 获得对象,执行解析
				field.set(thrifObj, null);
			}
		} catch (IllegalArgumentException | IllegalAccessException e) {
			logger.info("" + e);
		}
	}

	/**
	 * 
	 * @param type
	 *            1: fieldmap 中字段替换, 2: 不包含字段, 3: 只包含fieldmap 中字段
	 * @param fieldMap
	 * @param field
	 * @param mapData
	 * @return retData -1 失败,外部返回, 0 外部正常操作获取设置, 1 有返回结果,外部设置, 2 忽略,外部跳过
	 */
	public static Ref<Object> getMapDataMore(int type, Map<String, String> fieldMap, Field field,
			Map<String, Object> mapData) {

		Ref<Object> retObj = new Ref<Object>();
		switch (type) {
		case 1:
			if (fieldMap != null && fieldMap.containsKey(field.getName())) {
				try {
					// 找到指定的替换字段, 执行替换字段获取设置值, 否则返回继续替换
					String repKey = fieldMap.get(field.getName());
					if (mapData.containsKey(repKey))
						retObj.v = mapData.get(repKey);
					else
						retObj.v = mapData.get(field.getName());
				} catch (IllegalArgumentException e) {
					logger.info("" + e);
					retObj.c = -1;
				}
			} else
				retObj.c = 0;
			break;
		case 2:
			if (fieldMap != null && fieldMap.containsKey(field.getName())) {
				retObj.c = 2;
			} else
				retObj.c = 0;
			break;
		case 3:
			retObj.c = 2;
			if (fieldMap != null && fieldMap.containsKey(field.getName())) {
				try {
					// 找到指定的替换字段, 执行替换字段获取设置值, 否则返回继续替换
					String repKey = fieldMap.get(field.getName());
					retObj.c = 1;
					retObj.v = mapData.get(repKey);
				} catch (IllegalArgumentException e) {
					logger.info("" + e);
					retObj.c = -1;
				}
			}
			break;
		default:
		  break;
		}
		

		return retObj;

	}

	@SuppressWarnings("unused")
	private static Object getClassTypeValue(Class<?> typeClass, String value) {
		if (typeClass == int.class || typeClass == Integer.class) {
			return Integer.parseInt(value);
		} else if (typeClass == short.class || typeClass == Short.class) {
			return Short.parseShort(value);
		} else if (typeClass == byte.class) {
			return Byte.parseByte(value);
		} else if (typeClass == double.class || typeClass == Double.class) {
			return Double.parseDouble(value);
		} else if (typeClass == boolean.class || typeClass == Boolean.class) {
			return Boolean.parseBoolean(value);
		} else if (typeClass == float.class || typeClass == Float.class) {
			return Float.parseFloat(value);
		} else if (typeClass == long.class || typeClass == Long.class) {
			return Long.parseLong(value);
		} else {
			try {
				return typeClass.newInstance();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}
	}

	/**
	 * 
	 * @param javaBean
	 * @param Dname
	 * @param valObj
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	public static int doBeanFun(Object javaBean, String funSubName, Class<?> paramType, String funPrefix, Object valObj) {

		// 执行set方法
		Method method;
		try {
			String Dname = funSubName.substring(0, 1).toUpperCase() + funSubName.substring(1, funSubName.length());
			method = javaBean.getClass().getDeclaredMethod(funPrefix + Dname, new Class[] { paramType });
			method.invoke(javaBean, new Object[] { valObj });
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
				| SecurityException e) {
			logger.info("" + e);
			return -1;
		}
		return 1;

	}

	/**
	 * 
	 * @param thrifObj
	 * @param bAddNull
	 * @param fieldMap
	 *            预替换的字段, null 不替换
	 * @param type
	 *            1: fieldmap 中字段替换, 2: 不包含字段, 3: 只包含fieldmap 中字段
	 * @return
	 */
	static Map<String, Object> ThriftObjToMapHi(Object thrifObj, boolean bAddNull, final Map<String, String> fieldMap,
			final int type) {

		Map<String, Object> inMap = new HashMap<String, Object>();
		ThriftObjToMap(thrifObj, bAddNull, null, new CallBackIntface() {
			boolean bcontinue = true;

			@Override
			public boolean doTrans(Map<String, Object> outMap, String curKey, Object curObj) {
				switch (type) {
				case 1:
					if (fieldMap.containsKey(curKey) && fieldMap.get(curKey) != null) { // 找到需要替换的字段,并且非空
						outMap.put(fieldMap.get(curKey), curObj);
						bcontinue = false;
					}
					break;
				case 2:
					if (fieldMap.containsKey(curKey)) {
						bcontinue = false;
					}
					break;
				case 3:
					bcontinue = false;
					if (fieldMap.containsKey(curKey) && fieldMap.get(curKey) != null) {
						outMap.put(fieldMap.get(curKey), curObj);
						bcontinue = false;
					} else
						bcontinue = true;
					break;
				default:
				  break;
				}
				return bcontinue;
			}
		});
		return inMap;

	}
	
		/**
	 * obj 转 json,支持map key是object
	 * @param thrifObj
	 * @param bjson
	 * @param btop
	 * @return
	 */
	public static String MapObjToString(Object thrifObj, boolean bjson, boolean btop){
		
		StringBuilder sb = new StringBuilder();
		//普通基本数据类型
        if ( thrifObj.getClass() == Double.class || thrifObj.getClass() == Long.class || thrifObj.getClass() == Byte.class 
        		|| thrifObj.getClass() == String.class  || thrifObj.getClass() == ByteBuffer.class || thrifObj.getClass() == Integer.class ||thrifObj.getClass() == Boolean.class  ){
        	sb.append(thrifObj.toString());
        }//list 集合对象, 没有子元素递归处理
        else if ( thrifObj instanceof Set<?> ){
			Set<Object> objSet = (Set<Object>) thrifObj;
        	sb.append("[");
        	for ( Object j : objSet ){
        		sb.append(MapObjToString(j, bjson, true));
        		sb.append(",");
        	}
        	sb.deleteCharAt(sb.length()-1);
        	sb.append("]");
        }//list
        else if ( thrifObj instanceof List<?> ){
        	List<Object> objSet = (List<Object>) thrifObj;
        	sb.append("[");
        	for ( Object j : objSet ){
        		sb.append(MapObjToString(j, bjson, true));
        		sb.append(",");
        	}
        	sb.deleteCharAt(sb.length()-1);
        	sb.append("]");
        }//map
        else if ( thrifObj instanceof Map<?, ?> ){
        	sb.append("{");
			Map<Object, Object> objList = (Map<Object, Object>) thrifObj;
        	for ( Map.Entry<Object, Object> en : objList.entrySet() ){
        		String key = MapObjToString(en.getKey(), bjson, false);
        		key = key.replace("\"", "\\\"");
        		sb.append("\""+key+"\"");
        		sb.append(":");
        		sb.append(MapObjToString(en.getValue(), bjson, false));
        		sb.append(",");
        	}
        	sb.deleteCharAt(sb.length()-1);
        	sb.append("}");
        }//发现不是基本类型, 安装 thrift object 对象处理
        else{
        	sb.append("{");
        	MapObjToString(thrifObj, bjson, false);
        	sb.append("}");
        }
		return sb.toString();
	}
	
		
//	public static  void main(String[] test){
//		
//		Ref<Long> ref =  Ref.getLngO();
//		Long vv = new Long(2000L);
//		ref.v = vv;
//		
//		System.out.print(ref.v);
//		
//	}

}